home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / Snippets / Interapplication Communication / AECDEV⁄AEDAEMON / AECDEV.PPC.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-15  |  17.7 KB  |  383 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #   Apple Developer Technical Support
  4. #
  5. #   AppleEvent Sample Control Panel Device
  6. #
  7. #   AECDEV
  8. #
  9. #   AECDEV.c  -   C Source
  10. #   Written by  C.K. Haun
  11. #
  12. #   Copyright © 1991 Apple Computer, Inc.
  13. #   All rights reserved.
  14. #
  15. #   Versions:   1.0                 8/91
  16. #
  17. #   Components: AECdev.p          August 2, 1991
  18. #               AECDEV.PPC.c      August 2, 1991
  19. #
  20. #   AECDEV demonstrates the techniques needed to send AppleEvents
  21. #   from a CDEV/DA/INIT/Driver.
  22. #   Requires the sample AEDaemon to work.
  23. #
  24. ------------------------------------------------------------------------------*/
  25. /*------------------------------------------------------------------------------
  26. #   This file contains the AppleEvent code that creates the
  27. #   AppleEvent,  and PPC toolbox code that finds and transfers the data to the 
  28. #   Backgrounder.
  29. #   It also contains the PBCatSearch code.
  30. ------------------------------------------------------------------------------*/
  31.  
  32. #define __BUILDINGCDEV__
  33. #define __AECDEVPPC__
  34.  
  35. #include "NonAppAEVT.h"
  36. /* FindATarget prompts the user for a target application (through the PPC browser) */
  37. /* and a document for that application to open (with Standard File) */
  38. /* Once it's gotten that information, it bundles up the information about the */
  39. /* document to be opened into an APpleEvent list, adds the address of the target */
  40. /* application to the event, and passes the data to the routine that starts the PPC */
  41. /* transfer */
  42. void FindATarget(CDEVHnd storage)
  43. {
  44.     OSErr theErr = noErr;
  45.     LocationNameRec theLoc;
  46.     PortInfoRec theRec;
  47.     AEDesc theAddress, docDesc;
  48.     AEDescList theList;
  49.     AliasHandle myAlias;
  50.     StandardFileReply myReply;
  51.     TargetID theID;
  52.     AppleEvent theEvent;
  53.     Str32 tWext;
  54.     Str32 txWext;
  55.     /* Get the strings that will appear in the PPC browser */
  56.     GetIndString(&tWext, kStringsID, kBrowse1);
  57.     GetIndString(&txWext, kStringsID, kBrowse2);
  58.     /* Choose the Application you want to send the event to */
  59.     if (noErr == PPCBrowser(tWext, &txWext, false, &theLoc, &theRec, nil, nil)) {
  60.         /* Now I'll create the ODOC applevent */
  61.         /* Create the targetID for the selected application first */
  62.         theID.name = theRec.name;
  63.         theID.location = theLoc;
  64.         theErr = AECreateDesc(typeTargetID, (Ptr)&theID, sizeof(theID), &theAddress);
  65.         if (theErr == noErr) {
  66.         /* Create the whole event */
  67.             theErr = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &theAddress, kAutoGenerateReturnID, kAnyTransactionID,
  68.                                         &theEvent);
  69.             if (theErr == noErr) {
  70.                 /* now get a document to pass */
  71.                 StandardGetFile(nil, -1, nil, &myReply);
  72.                 if (myReply.sfGood) {
  73.                     /* odoc passed a list of FSSpecs, so make a list */
  74.                     /* even though this will only contain one spec, you still need a list */
  75.                     theErr = AECreateList(nil, 0, false, &theList);
  76.                     if (theErr == noErr) {
  77.                         /* create an alias out of the file spec */
  78.                         /* I'm not real sure why I did this, since there is a system coercion handler for */
  79.                         /* alias to FSSpec, but I'm paranoid (and goofy) */
  80.                         theErr = NewAlias(nil, &myReply.sfFile, &myAlias);
  81.                         if (theErr == noErr) {
  82.                             HLock((Handle)myAlias);
  83.                             /* now create an alias descriptor */
  84.                             theErr = AECreateDesc(typeAlias, (Ptr)*myAlias, GetHandleSize((Handle)myAlias), &docDesc);
  85.                             if (theErr == noErr) {
  86.                                 DisposHandle((Handle)myAlias);      /* no longer needed */
  87.                                 /* put it in the list */
  88.                                 theErr = AEPutDesc(&theList, 0, &docDesc);
  89.                                 if (theErr == noErr) {
  90.                                     /* and put the list in the event */
  91.                                     theErr = AEPutParamDesc(&theEvent, keyDirectObject, &theList);
  92.                                     if (theErr == noErr) {
  93.                                         /* now I'm passing the data portion of the AppleEvent to the handler */
  94.                                         /* that will open a PPC channel and pass the information along */
  95.                                         FireTheEvent(theEvent.dataHandle, storage);
  96.                                     }                       /* putparamdesc err */
  97.                                 }                           /* putDesc error */
  98.                                 /* dispose of all the appleevent strutures I've been using */
  99.                                 AEDisposeDesc(&docDesc);
  100.                             }                               /* docDesc creation error */
  101.                         }                                   /* alias creation error */
  102.                         AEDisposeDesc(&theList);
  103.                     }                                       /* list create error */
  104.                     
  105.                 }                                           /* standardfile cancel */
  106.                 AEDisposeDesc(&theEvent);
  107.             }                                               /* event create error */
  108.             AEDisposeDesc(&theAddress);
  109.         }                                                   /* desc 1 error */
  110.     }                                                       /* browser cancel or error */
  111. } /* end FindATarget */
  112.  
  113. /* FindAEBuddy searches for the port to use to send the event.  In this */
  114. /* case I'm using my AEDaemon application to send events for me.  */
  115. /* So, if first see if it's available by looking for it's port with */
  116. /* IPCListPorts.  If it isn't available, I search for it by */
  117. /* creator and file type with PBCatSearch, and launch it if I find it */
  118. /* Of course, if I launch it myself I need to give it some time */
  119. /* to register itself and come up in the PPC port list, so I'll set */
  120. /* a flag and go away for a while, checking back periodically until */
  121. /* the port comes up */
  122. /* You can use AEBuddy also for your app, though I'd change the name.... */
  123. void FindAEBuddy(CDEVHnd storage)
  124. {
  125.     Byte csState;
  126.     CDEVPtr tempPtr;
  127.     CursHandle watch;
  128.     /* Use NewPtrClear for these, so you don't have to worry about having */
  129.     /* garbage in the parameters to start */
  130.     IPCListPortsPBPtr listPtr = NewPtrClear(sizeof(IPCListPortsPBRec));
  131.     PPCPortPtr portWanted = NewPtrClear(sizeof(PPCPortRec));
  132.     LaunchParamBlockRec launchThis;
  133.     short realCount;
  134.     OSErr myError;
  135.     /* find AEBuddy, open our port, and pass the data */
  136.     /* remember NewPtrClear gave me a zeroed record, so all the parameters */
  137.     /* that I wanted nil'ed are. */
  138.     /* BY THE WAY: I could use the PPCBrowser again here, of course.  */
  139.     /* but remember, most of your users will have no idea that this CDEV is */
  140.     /* using another process, since faceless backgrounders don't show up */
  141.     /* in any list that most users can see */
  142.     watch = GetCursor(watchCursor);
  143.     SetCursor(*watch);                                      /* wait cursor */
  144.     csState = HGetState((Handle)storage);
  145.     HLock((Handle)storage);
  146.     tempPtr = *storage;                                     /* dereference this for clarity */
  147.     listPtr->requestCount = 1;                              /* only want one of them */
  148.     listPtr->portName = portWanted;
  149.     /* fill in the port a bit */
  150.     portWanted->name[0] = 1;                                /* making a "=" string here, telling IPCListPorts */
  151.     portWanted->name[1] = '=';                              /* that I don't care about the name of the port */
  152.     portWanted->portKindSelector = ppcByCreatorAndType;
  153.     portWanted->u.port.creator = 'MOOB';
  154.     portWanted->u.port.type = 'APPL';
  155.     /* the location name will be nil, since I want to get the thing on the */
  156.     /* local machine, not across the vast net */
  157.     listPtr->locationName = nil;
  158.     listPtr->bufferPtr = (PortInfoArrayPtr)NewPtrClear(sizeof(PortInfoRec));
  159.     /* we're only asking for one, so we only need one array space allocated */
  160.     
  161.     myError = IPCListPorts(listPtr, false);                 /* getting it syncronously */
  162.     realCount = listPtr->actualCount;
  163.     /* so we don't forget */
  164.     if (myError == noErr) {
  165.         if (realCount == 0 && (*storage)->searchForTarget == false) {
  166.             /* The following segment is the PBCatSearch area */
  167.             
  168.             /* Couldn't find the port and we haven't launched it ourselves yet. */
  169.             /* So, let's see if we can find the app and launch it */
  170.             /* ourselves */
  171.             /* make a pointer to the block */
  172.             CSParamPtr csBlockPtr = NewPtrClear(sizeof(CSParam));
  173.             long dirIDUnused;
  174.             Str32 nulString = "\p";
  175.             /* initialize the parameter block */
  176.             if (csBlockPtr) {
  177.                 csBlockPtr->ioSearchInfo1 = (CInfoPBPtr)NewPtrClear(sizeof(CInfoPBRec));
  178.                 csBlockPtr->ioSearchInfo2 = (CInfoPBPtr)NewPtrClear(sizeof(CInfoPBRec));
  179.                 if (csBlockPtr->ioSearchInfo1 && csBlockPtr->ioSearchInfo2) {
  180.                     csBlockPtr->ioMatchPtr = (FSSpecPtr)NewPtrClear(sizeof(FSSpec) * 1);        /* only looking for 1 */
  181.                     if (csBlockPtr->ioMatchPtr) {
  182.                         /* Now see if we can create an optimization buffer */
  183.                         csBlockPtr->ioOptBuffer = NewPtr(2048);
  184.                         if (csBlockPtr->ioOptBuffer)
  185.                             csBlockPtr->ioOptBufSize = 2048;
  186.                         else
  187.                             csBlockPtr->ioOptBufSize = 0;       /* no buffer, sorry */
  188.                         csBlockPtr->ioReqMatchCount = 1;
  189.                         csBlockPtr->ioSearchTime = 0;       /* no timeout */
  190.                     }
  191.                 }
  192.             }
  193.             /* check all my memory allocations here */
  194.             if (csBlockPtr->ioSearchInfo1 && csBlockPtr->ioSearchInfo2 && csBlockPtr->ioMatchPtr) {
  195.                 /* had memory, continue */
  196.                 HGetVol(nil, &csBlockPtr->ioVRefNum, &dirIDUnused);     /* get default volume for search */
  197.                 csBlockPtr->ioSearchInfo1->hFileInfo.ioNamePtr = nil;
  198.                 csBlockPtr->ioSearchInfo2->hFileInfo.ioNamePtr = nil;
  199.                 csBlockPtr->ioSearchInfo1->hFileInfo.ioFlFndrInfo.fdCreator = 'MOOB';
  200.                 csBlockPtr->ioSearchInfo1->hFileInfo.ioFlFndrInfo.fdType = 'APPL';
  201.                 csBlockPtr->ioSearchBits = fsSBFlFndrInfo;
  202.                 csBlockPtr->ioSearchInfo2->hFileInfo.ioFlFndrInfo.fdCreator = 0xFFFFFFFF;
  203.                 csBlockPtr->ioSearchInfo2->hFileInfo.ioFlFndrInfo.fdType = 0xFFFFFFFF;
  204.                 myError = PBCatSearch(csBlockPtr, false);       /* search sync */
  205.                 if (myError == noErr && csBlockPtr->ioActMatchCount != 0) {
  206.                     /* we found it, so launch it */
  207.                     launchThis.launchBlockID = extendedBlock;
  208.                     launchThis.launchEPBLength = extendedBlockLen;
  209.                     launchThis.launchFileFlags = nil;
  210.                     launchThis.launchControlFlags = launchContinue + launchNoFileFlags;
  211.                     launchThis.launchAppSpec = &csBlockPtr->ioMatchPtr[0];
  212.                     myError = LaunchApplication(&launchThis);
  213.                     if (myError == noErr) {
  214.                         /* it launched fine.  Set a flag so we can */
  215.                         /* check periodically until it's */
  216.                         /* PPC port comes up */
  217.                         (*storage)->searchForTarget = true;
  218.                     }
  219.                 } else {
  220.                     /* PBCat failed, we have no buddy on this volume.  Oh well */
  221.                     (*storage)->noBuddy = true;
  222.                 }
  223.             }                                               /* out of memory error */
  224.             if (csBlockPtr) {
  225.                 /* clean up what we allocated */
  226.                 if (csBlockPtr->ioSearchInfo1)
  227.                     DisposPtr((Ptr)csBlockPtr->ioSearchInfo1);
  228.                 if (csBlockPtr->ioSearchInfo2)
  229.                     DisposPtr((Ptr)csBlockPtr->ioSearchInfo2);
  230.                 if (csBlockPtr->ioMatchPtr)
  231.                     DisposPtr((Ptr)csBlockPtr->ioMatchPtr);
  232.                 if (csBlockPtr->ioOptBuffer)
  233.                     DisposPtr((Ptr)csBlockPtr->ioOptBuffer);
  234.                 DisposPtr((Ptr)csBlockPtr);
  235.             }
  236.             
  237.             /* catsearch section end */
  238.         } else {
  239.             PortInfoPtr portInfoTemp = (PortInfoPtr)listPtr->bufferPtr;
  240.             tempPtr->myPPCBlock->buddyPortPtr = (PPCPortPtr)NewPtrClear(sizeof(PPCPortRec));
  241.             /* we have a port to send to.  So, we'll first clear that flag... */
  242.             (*storage)->searchForTarget = false;
  243.             BlockMove((Ptr)&portInfoTemp->name, (Ptr)tempPtr->myPPCBlock->buddyPortPtr, sizeof(PPCPortRec));
  244.             
  245.         }
  246.     }                                                       /* listports err */
  247.     /* clean up the IPCListPorts memory */
  248.     if (listPtr->bufferPtr)
  249.         DisposPtr((Ptr)listPtr->bufferPtr);
  250.     if (listPtr)
  251.         DisposPtr((Ptr)listPtr);
  252.     if (portWanted)
  253.         DisposPtr((Ptr)portWanted);
  254.     
  255.     /* NOTE: I don't need to clean up listPtr->bufferPtr since I moved this into */
  256.     /* our other structure for later use */
  257.     InitCursor();
  258. } /* end FindAEBuddy */
  259.  
  260. /* FireTheEvent starts the PPC process.  It opens a port for us, and connects us to */
  261. /* AEBuddy.  The, through a series of asyncronous PPC calls, it transfers all the data */
  262. /* that makes up the APpleEvent we want to send. */
  263. void FireTheEvent(Handle packedEvent, CDEVHnd storage)
  264. {
  265.     /* all this will happen asyncronously, so no error back from this routine */
  266.     /* The first thing we do is open our own port, that completion routine will */
  267.     /* start a session with our target, that completion routine will write the data, */
  268.     /* that completion roiutine will end the session, then that completion routine */
  269.     /* will close the port.  */
  270.     /* Open our port */
  271.     /* first check to see if we've already opened a port.  If not, open one */
  272.     
  273.     Str32 myName;
  274.     PPCPortPtr myPort = (*storage)->myPPCBlock->myPort;
  275.     PPCOpenPBPtr openPtr = (PPCOpenPBPtr)(*storage)->myPPCBlock;
  276.     /* and once more, local 4 byte space is cheap */
  277.     MyPPCRecPtr ourPtr = (MyPPCRecPtr)openPtr;
  278.     GetIndString(&myName, kStringsID, kMyName);
  279.     /* take the passed handle, make it our own ptr */
  280.     ourPtr->bufferSize = GetHandleSize(packedEvent);
  281.     ourPtr->buffer = NewPtr(GetHandleSize(packedEvent));
  282.     HLock(packedEvent);
  283.     BlockMove((Ptr)*packedEvent, ourPtr->buffer, GetHandleSize(packedEvent));
  284.     /*  Create our port */
  285.     myPort->nameScript = 0;
  286.     BlockMove((Ptr)&myName, (Ptr)&myPort->name, myName[0] + 1);
  287.     myPort->portKindSelector = ppcByCreatorAndType;
  288.     myPort->u.port.creator = 'ckh1';
  289.     myPort->u.port.type = 'APPL';
  290.     openPtr->ioCompletion = (PPCCompProcPtr)OpenComplete;
  291.     
  292.     openPtr->serviceType = ppcServiceRealTime;              /* only valid one under 7.0 */
  293.     openPtr->resFlag = 0;
  294.     openPtr->portName = myPort;
  295.     openPtr->locationName = nil;
  296.     openPtr->networkVisible = false;
  297.     PPCOpen(openPtr, true);
  298.     (*storage)->eventPending = true;
  299. }
  300.  
  301. void OpenComplete(PPCStartPBPtr p)
  302. {
  303.     OSErr myErr;
  304.     /* cast this so it's easier to see */
  305.     MyPPCRecPtr ourPtr = (MyPPCRecPtr)p;
  306.     myErr = p->ioResult;
  307.     if (myErr == noErr) {
  308.         ourPtr->ourPort = p->portRefNum;
  309.        /* We opened our port successfully, so now connect to the buddy */
  310.     p->ioCompletion = (PPCCompProcPtr)StartComplete;
  311.     p->portName = ourPtr->buddyPortPtr;
  312.     p->locationName = nil;
  313.     PPCStart((PPCStartPBPtr)p, true);
  314.      } else {
  315.         DebugStr("\p error in opencomp");
  316.     }
  317. }
  318.  
  319. void StartComplete(PPCWritePBPtr p)
  320. {
  321.     OSErr fred;
  322.     MyPPCRecPtr ourPtr = (MyPPCRecPtr)p;
  323.     fred = p->ioResult;
  324.     if (fred == noErr) {
  325.     /* we started a session.  In this case, we were allowed to connect without authentication */
  326.     /* so we can start blasting data now */
  327.         p->bufferLength = ourPtr->bufferSize;
  328.         p->bufferPtr = ourPtr->buffer;
  329.         p->more = false;
  330.         /* pass ???? as the creator, the AEBuddy doesn't care who is sending it data */
  331.         p->blockCreator = kGenericCreator;
  332.         /* telling the buddy what type of data I'm sending */
  333.         /* since it _only_ accepts one type */
  334.         p->blockType = kMyTypeOfData;                       
  335.         p->ioCompletion = (PPCCompProcPtr)WriteComplete;
  336.         ourPtr->currentSessionRef = p->sessRefNum;
  337.         PPCWrite((PPCWritePBPtr)p, (Boolean)true);
  338.     } else {
  339.         DebugStr("\p error in startcomp");
  340.         p->ioCompletion = (PPCCompProcPtr)EndComplete;
  341.         PPCEnd((PPCEndPBPtr)p, true);
  342.         
  343.     }
  344. }
  345.  
  346. void WriteComplete(PPCEndPBPtr p)
  347. {
  348.     MyPPCRecPtr ourPtr = (MyPPCRecPtr)p;
  349.     OSErr fred;
  350.     fred = p->ioResult;
  351.     if (fred == noErr) {
  352.     /* We wrote everything we wanted to, time to end the session */
  353.         p->ioCompletion = (PPCCompProcPtr)EndComplete;
  354.         PPCEnd(p, true);
  355.     } else {
  356.         DebugStr("\p error in writecomp");
  357.         p->ioCompletion = (PPCCompProcPtr)EndComplete;
  358.         PPCEnd(p, true);
  359.         
  360.     }
  361. }
  362.  
  363. void EndComplete(PPCClosePBPtr p)
  364. {
  365.     MyPPCRecPtr ourPtr = (MyPPCRecPtr)p;
  366.     /* clear our session ref number please */
  367.     if (p->ioResult) {
  368.         DebugStr("\p error in endcomp");
  369.     }
  370.     /* I'm closing our port here, you could of course leave it open */
  371.     /* for repeated requests.  One reason why I'm not leaving it open is */
  372.     /* because I don't want anyone to try and talk to us */
  373.     ourPtr->currentSessionRef = nil;
  374.     /* and close the session out */
  375.     p->ioCompletion = nil;
  376.     PPCClose(p, false);
  377.     ourPtr->pB.openParam.portRefNum = nil;
  378. }
  379.  
  380.  
  381. #undef __BUILDINGCDEV__
  382. #undef __AECDEVPPC__
  383.